package grpc

import (
	"context"
	"gitverse.ru/synapse/kubelatte/pkg/grpc/proto"
	"gitverse.ru/synapse/kubelatte/pkg/logs"
	"gitverse.ru/synapse/kubelatte/pkg/storage"
	"go.uber.org/zap"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"reflect"
	"strconv"
	"testing"
)

var port = 8686

func Test_sendEvent(t *testing.T) {
	type args struct {
		action string
		data   string
		tp     string
	}
	tests := []struct {
		name    string
		args    args
		wantErr bool
	}{
		{
			name: "trigger update unexpected data",
			args: args{
				action: "update",
				data:   "true",
				tp:     "trigger",
			},
			wantErr: true,
		},
		{
			name: "template update unexpected data",
			args: args{
				action: "update",
				data:   "true",
				tp:     "template",
			},
			wantErr: true,
		},
		{
			name: "scope update unexpected data",
			args: args{
				action: "update",
				data:   "true",
				tp:     "scope",
			},
			wantErr: true,
		},
		{
			name: "namespace delete unexpected data",
			args: args{
				action: "delete",
				data:   "true",
				tp:     "namespace",
			},
			wantErr: true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := sendEvent(tt.args.action, tt.args.data, tt.args.tp); (err != nil) != tt.wantErr {
				t.Errorf("sendEvent() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func getGRPCClient(t *testing.T, port int) proto.ConfigSyncClient {
	t.Helper()

	var opts []grpc.DialOption
	var err error
	serverAddr := "localhost:" + strconv.Itoa(port)
	opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))

	conn, err := grpc.Dial(serverAddr, opts...)
	if err != nil {
		t.Fatalf("[SyncController] fail to dial: %s", err.Error())
	}
	cli := proto.NewConfigSyncClient(conn)
	return cli
}

func TestConfigSyncServer_Ping(t *testing.T) {
	logs.Logger = zap.NewNop()
	StartSyncServer(port)

	cli := getGRPCClient(t, port)

	_, err := cli.Ping(context.Background(), &proto.EmptyMessage{})
	if err != nil {
		t.Fatal("wrong err, expected nil, got:", err)
	}

}

func TestGrpcConnect(t *testing.T) {
	logs.Logger = zap.NewNop()

	StartSyncServer(port)
	//defer stop()

	cli := getGRPCClient(t, port)

	_, err := cli.Ping(context.Background(), &proto.EmptyMessage{})
	if err != nil {
		t.Fatal("wrong err, expected nil, got:", err)
	}
}

func TestConfigSyncServer_GetScopesTemplatesTriggers(t *testing.T) {
	StartSyncServer(port)

	cli := getGRPCClient(t, port)
	type args struct {
		in0 context.Context
		in1 *proto.EmptyMessage
	}
	tests := []struct {
		name    string
		args    args
		want    interface{}
		wantErr bool
	}{
		{
			name: "Scopes",
			args: args{
				in0: context.Background(),
				in1: &proto.EmptyMessage{},
			},
			want:    &proto.Scopes{},
			wantErr: false,
		},
		{
			name: "Templates",
			args: args{
				in0: context.Background(),
				in1: &proto.EmptyMessage{},
			},
			want:    &proto.Templates{},
			wantErr: false,
		},
		{
			name: "Triggers",
			args: args{
				in0: context.Background(),
				in1: &proto.EmptyMessage{},
			},
			want:    &proto.Triggers{},
			wantErr: false,
		},
	}
	storage.Storage = &storage.StorageController{}
	storage.Storage.Start(false, false)

	t.Run(tests[0].name, func(t *testing.T) {

		got, err := cli.GetScopes(tests[0].args.in0, tests[0].args.in1)
		if (err != nil) != tests[0].wantErr {
			t.Errorf("GetScopes() error = %v, wantErr %v", err, tests[0].wantErr)
			return
		}
		wa := tests[0].want.(*proto.Scopes)

		if !reflect.DeepEqual(got.Json, wa.Json) {
			t.Errorf("GetScopes() got = %v, want %v", got, tests[0].want)
		}
	})

	t.Run(tests[1].name, func(t *testing.T) {

		got, err := cli.GetTemplates(tests[1].args.in0, tests[1].args.in1)
		if (err != nil) != tests[1].wantErr {
			t.Errorf("GetScopes() error = %v, wantErr %v", err, tests[1].wantErr)
			return
		}
		wa := tests[1].want.(*proto.Templates)

		if !reflect.DeepEqual(got.Json, wa.Json) {
			t.Errorf("GetScopes() got = %v, want %v", got, tests[1].want)
		}
	})

	t.Run(tests[2].name, func(t *testing.T) {

		got, err := cli.GetTriggers(tests[2].args.in0, tests[2].args.in1)
		if (err != nil) != tests[2].wantErr {
			t.Errorf("GetScopes() error = %v, wantErr %v", err, tests[2].wantErr)
			return
		}
		wa := tests[2].want.(*proto.Triggers)

		if !reflect.DeepEqual(got.Json, wa.Json) {
			t.Errorf("GetScopes() got = %v, want %v", got, tests[2].want)
		}
	})
}
